package fourThread;

import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.*;

/**
 * @author Xu,
 * @data 2020/12/13，
 * @time 10:51
 * 后两个线程时间累计有差错
 * 一直出现累计时间有差错，原因在：
 * 1. 每次上一个线程区域的in只扫了下一个区域的out，应该三个区域都扫遍，防止少数车辆长期停车；
 * 2. 处理各线程临界的in、out数据，应在所有线程执行完再处理，否则该部分的线程执行时，critical2和critical3都仍为空，导致累计时间差错。
 */
public class FourThread {
    private static ArrayList<ArrayList<String>> log = new ArrayList<>();
    private static ArrayList<ArrayList<String>> myLog = new ArrayList<>();
    private static ArrayList<ArrayList<String>> critical1 = new ArrayList<>();
    private static ArrayList<ArrayList<String>> critical2 = new ArrayList<>();
    private static ArrayList<ArrayList<String>> critical3 = new ArrayList<>();
    private static int count = 0;
    private static long sumTime = 0;
    private static boolean finalI = true;
    private static Date date1 = null;
    private static Date date2 = null;
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        String path = "./src/carsLog.txt";
        readData(path);
        System.out.println("数据导入data时间：" + (System.currentTimeMillis() - start)/1000.0 + " s");
        searchData();
        parkTime();
        cal_critical();
        System.out.println("进出车次数：" + count/2);
        System.out.println("累计停放秒数：" + sumTime + " s");
        long end = System.currentTimeMillis();
        System.out.println("runtime: " + (end - start)/1000.0 + " s");
    }

    /**
     * 停车计数、计时
     */
    public  static void parkTime(){
        byte[] lock = new byte[0];
        ExecutorService executorService = new ThreadPoolExecutor(4, 5, 0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(10),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        executorService.execute(
                new Runnable(){
                    @Override
                    public void run() {
                        synchronized (lock) {
                            if(!finalI) {
                                try {
                                    lock.wait();
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                            for (int i=0; i<myLog.size()/4; i++){
                                if(myLog.get(i).get(3).equals("in")){
                                    try {
                                        date1 = sdf.parse(myLog.get(i).get(0));
                                    } catch (ParseException e) {
                                        e.printStackTrace();
                                    }
                                    int j;
                                    for(j=i; j<myLog.size()/4; j++){
                                        if(myLog.get(j).get(2).equals(myLog.get(i).get(2)) && "out".equals(myLog.get(j).get(3))){
                                            try {
                                                date2 = sdf.parse(myLog.get(j).get(0));
                                            } catch (ParseException e) {
                                                e.printStackTrace();
                                            }
                                            sumTime += (date2.getTime() - date1.getTime())/1000;
                                            break;
                                        }
                                    }
                                    //边缘处理
                                    if (j == myLog.size()/4) {
                                        critical1.add(myLog.get(i));
                                    }
                                }
                            }
                            finalI = false;
                            lock.notify();
                        }
                    }
                });
        executorService.execute(
                new Runnable(){
                    @Override
                    public void run() {
                        synchronized (lock){
                            if(finalI){
                                try {
                                    lock.wait();
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                            for (int i=myLog.size()/4; i<myLog.size()/2; i++){
                                if(myLog.get(i).get(3).equals("in")){
                                    try {
                                        date1 = sdf.parse(myLog.get(i).get(0));
                                    } catch (ParseException e) {
                                        e.printStackTrace();
                                    }
                                    int j;
                                    for(j=i; j<myLog.size()/2; j++){
                                        if(myLog.get(j).get(2).equals(myLog.get(i).get(2)) && "out".equals(myLog.get(j).get(3))){
                                            try {
                                                date2 = sdf.parse(myLog.get(j).get(0));
                                            } catch (ParseException e) {
                                                e.printStackTrace();
                                            }
                                            sumTime += (date2.getTime() - date1.getTime())/1000;
                                            break;
                                        }
                                    }
                                    if (j == myLog.size()/2) {
                                        critical2.add(myLog.get(i));
                                    }
                                }
                            }

                            finalI = true;
                            lock.notify();
                        }
                    }

                });
        executorService.execute(
                new Runnable(){
                    @Override
                    public void run() {
                        Date date1 = null;
                        Date date2 = null;
                        synchronized (lock){
                            if(!finalI){
                                try {
                                    lock.wait();
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                            for (int i=myLog.size()/2; i<myLog.size()/2+myLog.size()/4; i++){
                                if(myLog.get(i).get(3).equals("in")){
                                    try {
                                        date1 = sdf.parse(myLog.get(i).get(0));
                                    } catch (ParseException e) {
                                        e.printStackTrace();
                                    }
                                    int j;
                                    for(j=i; j<myLog.size()/2+myLog.size()/4; j++){
                                        if(myLog.get(j).get(2).equals(myLog.get(i).get(2)) && "out".equals(myLog.get(j).get(3))){
                                            try {
                                                date2 = sdf.parse(myLog.get(j).get(0));
                                            } catch (ParseException e) {
                                                e.printStackTrace();
                                            }
                                            sumTime += (date2.getTime() - date1.getTime())/1000;
                                            break;
                                        }
                                    }
                                    if (j == myLog.size()/2+myLog.size()/4) {
                                        critical3.add(myLog.get(i));
                                    }
                                }
                            }
                            finalI = false;
                            lock.notify();
                        }
                    }

                });
        executorService.execute(
                new Runnable(){
                    @Override
                    public void run() {
                        Date date1 = null;
                        Date date2 = null;
                        synchronized (lock){
                            if(finalI){
                                try {
                                    lock.wait();
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                            for (int i=myLog.size()/4+myLog.size()/2; i<myLog.size(); i++){
                                if(myLog.get(i).get(3).equals("in")){

                                    try {
                                        date1 = sdf.parse(myLog.get(i).get(0));
                                    } catch (ParseException e) {
                                        e.printStackTrace();
                                    }
                                    int j;
                                    for(j=i; j<myLog.size(); j++){
                                        if(myLog.get(j).get(2).equals(myLog.get(i).get(2)) && "out".equals(myLog.get(j).get(3))){
                                            try {
                                                date2 = sdf.parse(myLog.get(j).get(0));
                                            } catch (ParseException e) {
                                                e.printStackTrace();
                                            }
                                            sumTime += (date2.getTime() - date1.getTime())/1000;
                                            break;
                                        }
                                    }
                                }
                            }
                            finalI = true;
                            lock.notify();
                        }
                    }

                });
        executorService.shutdown();
        while(!executorService.isTerminated()){ }
    }

    /**
     * 找到自己学号的停车场，并统计进出次数
     * 记录每辆车的停放时间的总和
     */
    public static void searchData(){
        for(int i=0;i<log.size();i++){
            if("201825010318".equals(log.get(i).get(1))){
                myLog.add(log.get(i));
                count++;
            }
        }

    }

    /**
     * 读取数据
     * @param path
     * @return
     */
    public  static void readData(String path){
        ArrayList<String> t = null;
        try {
            InputStreamReader isr = new InputStreamReader(new FileInputStream(new File(path)));
            BufferedReader br = new BufferedReader(isr);
            String str = null;
            while((str = br.readLine()) != null){
                t = new ArrayList<String>();
                String[] str1 = str.split(",");
                for(int i = 0; i < str1.length ; i++) {
                    t.add(str1[i]);
                }
                log.add(t);
            }
            br.close();
            isr.close();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("读取文件内容出错！");
        }
    }

    /**
     * check一下
     */
    public static void show1(){
        for(int i=0;i<myLog.size();i++){
            System.out.println(myLog.get(i));
        }
    }

    public static void cal_critical(){
        //out匹配in
        for(int k=0;k<critical1.size();k++){
            for(int m=myLog.size()/4;m<myLog.size();m++){
                try {
                    date1 = sdf.parse(critical1.get(k).get(0));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                if(critical1.get(k).get(2).equals(myLog.get(m).get(2))){
                    try {
                        date2 = sdf.parse(myLog.get(m).get(0));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    sumTime += (date2.getTime() - date1.getTime())/1000;
                    break;
                }
            }
        }
        //out匹配in
        for(int k=0;k<critical2.size();k++){
            for(int m=myLog.size()/2;m<myLog.size();m++){
                try {
                    date1 = sdf.parse(critical2.get(k).get(0));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                if(critical2.get(k).get(2).equals(myLog.get(m).get(2))){
                    try {
                        date2 = sdf.parse(myLog.get(m).get(0));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    sumTime += (date2.getTime() - date1.getTime())/1000;
                    break;
                }
            }
        }
        //out匹配in
        for(int k=0;k<critical3.size();k++){
            for(int m=myLog.size()/4+myLog.size()/2;m<myLog.size();m++){
                try {
                    date1 = sdf.parse(critical3.get(k).get(0));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                if(critical3.get(k).get(2).equals(myLog.get(m).get(2))){
                    try {
                        date2 = sdf.parse(myLog.get(m).get(0));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    sumTime += (date2.getTime() - date1.getTime())/1000;
                    break;
                }
            }
        }

    }
}
